package Data;

import java.util.Arrays;
import java.io.BufferedWriter;
import java.io.File;


import myio.FileIO;
import mymath.ArrayComparator;

/* Manages data that consists of a 0/1-matrix */

public abstract class datamanager {

	
	public abstract void loadData(String datafile);
	
	public abstract int numInstances();
	
	public abstract int numAttributes();
	
	public abstract int[][] getData();
	
	public abstract int getdataitem(int instance, int attribute);
	
	public abstract String getAttributeName(int ind);
	
	/* Computes matrix containing mutual information between all clusterings and all attributes
	 * 
	 * clusterinfo is matrix returned by clusterparser.readClusters
     * 
     * result has dimensions [#clusterings][#attributes], 
     * and result[i][j]: mutual information of j'th attribute with i'th clustering
     *     
     */
	public static double[][] mutualinformation(datamanager dm, int[][] clusterinfo){
	    double[][] mi = new double[clusterinfo.length-1][dm.numAttributes()];
	    for (int i=0;i<clusterinfo.length-1;i++){ /* iterate over the clusterings */
	    	int clussize = clusterinfo[i][1];
	    	for (int j=0; j<dm.numAttributes(); j++){
	    		double[][] joint = new double[clussize][2]; /* Matrix for the joint distribution counts of i'th clustering and current plant */
	    		double[] plantmarginal = new double[2]; 
	    		double[] layermarginal = new double[clussize];
	    		/* Iterate over the sites: */
	    		for (int h=0; h<dm.numInstances(); h++){
	    			joint[clusterinfo[i][h+2]][dm.getdataitem(h,j)]++;
	    			plantmarginal[dm.getdataitem(h,j)]++;
	    			layermarginal[clusterinfo[i][h+2]]++;	
	    		}
	    		mi[i][j]=0;
	    		for (int ii =0; ii<clussize; ii++){
	    			for (int kk=0; kk<=1; kk++){
	    				mi[i][j]=mi[i][j] + 
	    							joint[ii][kk]/dm.numInstances()*Math.log(joint[ii][kk]*dm.numInstances()/(layermarginal[ii]*plantmarginal[kk])); 
	    			}
	    		}
	    	}
	    }
	    return mi;
	}
	
	/* Returns MI values of attributes in decreasing order
	 * 
	 * result has dimension [#attributes][2] with
	 * result[j][0] : MI value of attribute with j'th highest MI
	 * result[j][1] : index of attribute with j'th highest MI
	 *  
	 */
	  public static double[][] sortMI(double[][] mimatrix, int clustering){
		  double[][] result = new double[mimatrix[clustering].length][2];
		  for (int i=0;i<result.length;i++){
			  result[i][0]= mimatrix[clustering][i];
			  result[i][1]= i;
		  }
		  Arrays.sort(result,new ArrayComparator(0,true));
		  return result;
	  }
	  
	  /* Saves an MI matrix (transposed) to data file in arff format
	   * 
	   *
	   */
	  public static void saveMI(datamanager dm, double[][] mimatrix, String outputfile){
		  try{
			  BufferedWriter writer = FileIO.openOutputFile(outputfile);
			  writer.write("@relation 'mi' " + '\n');
			  writer.write("@attribute Attribute string" + '\n');
			  for (int i=0;i<mimatrix.length;i++){
				  writer.write("@attribute mi_" + i + " numeric" + '\n');
			  }
			  writer.write("@data"+ '\n');
			  for (int j=0;j<mimatrix[0].length;j++){
				  writer.write(dm.getAttributeName(j) +",");
				  for (int h=0; h<mimatrix.length-1; h++){
					  writer.write(mimatrix[h][j] + ","); 
				  }		
				  writer.write(mimatrix[mimatrix.length-1][j] + " " + '\n' );
			  }
			  writer.close();
		  }
		  catch (Exception e) {
			  System.err.println(e);
		  }
	  }
	
}
